/*
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.

  Keepass2Android is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Keepass2Android is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Keepass2Android.  If not, see <http://www.gnu.org/licenses/>.
  */

using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Widget;
using Android.Graphics.Drawables;
using Android.Content.Res;
using KeePassLib;
using Android.Graphics;
using Android.Preferences;
using keepass2android;

namespace keepass2android
{
  /// <summary>
  /// Factory to create password icons
  /// </summary>
  public class DrawableFactory : IDrawableFactory
  {
    private static Drawable _blank;
    private static int _blankWidth = -1;
    private static int _blankHeight = -1;

    /** customIconMap
 *  Cache for icon drawable. 
 *  Keys: UUID, Values: Drawables
 */
    private readonly Dictionary<PwUuid, Drawable> _customIconMap = new Dictionary<PwUuid, Drawable>(new PwUuidEqualityComparer());

    /** standardIconMap
 *  Cache for icon drawable. 
 *  Keys: Integer, Values: Drawables
 */
    private readonly Dictionary<int/*icon key*/, Drawable> _standardIconMap = new Dictionary<int, Drawable>();

    public void AssignDrawableTo(ImageView iv, Context context, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup)
    {
      Drawable draw = GetIconDrawable(context, db, icon, customIconId, forGroup);
      if (draw != null)
      {
        draw = draw.Mutate();
        iv.SetImageDrawable(draw);
      }

      else
        Kp2aLog.LogUnexpectedError(new Exception("icon not found : " + icon));
    }

    public Drawable GetIconDrawable(Context context, PwDatabase db, PwIcon icon, PwUuid customIconId, bool forGroup)
    {
      if ((customIconId != null) && (!customIconId.Equals(PwUuid.Zero)))
      {
        return GetIconDrawable(context, db, customIconId);
      }
      return GetIconDrawable(context, icon, forGroup);
    }

    public bool IsWhiteIconSet
    {
      get
      {
        var context = LocaleManager.LocalizedAppContext;
        string packageName = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext).GetString("IconSetKey", context.PackageName);
        //assume that at the momemt only the built in icons are white
        return packageName == context.PackageName;
      }
    }

    private static void InitBlank(Context context)
    {
      if (_blank == null)
      {
        _blank = context.Resources.GetDrawable(Resource.Drawable.ic99_blank);
        _blankWidth = _blank.IntrinsicWidth;
        _blankHeight = _blank.IntrinsicHeight;
      }
    }

    public Drawable GetIconDrawable(Context context, PwIcon icon, bool forGroup)
    {
      //int resId = DefaultIcons.IconToResId (icon, forGroup);
      int dictKey = GetDictionaryKey(icon, forGroup);

      Drawable draw;
      if (!_standardIconMap.TryGetValue(dictKey, out draw))
      {
        string packageName = PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext).GetString("IconSetKey", context.PackageName);

        Resources res;
        try
        {
          res = context.PackageManager.GetResourcesForApplication(packageName);
        }
        catch (Exception)
        {
          //can happen after uninstalling icons
          packageName = context.PackageName;
          res = context.PackageManager.GetResourcesForApplication(packageName);
          PreferenceManager.GetDefaultSharedPreferences(LocaleManager.LocalizedAppContext)
              .Edit()
              .PutString("IconSetKey", packageName)
              .Commit();
        }

        try
        {
          int resId = GetResourceId(res, dictKey, packageName);
          if (resId == 0)
            draw = context.Resources.GetDrawable(Resource.Drawable.ic99_blank);
          else
            draw = res.GetDrawable(resId);

        }
        catch (System.Exception e)
        {
          Kp2aLog.LogUnexpectedError(e);
          draw = context.Resources.GetDrawable(Resource.Drawable.ic99_blank);
        }

      }
      _standardIconMap[dictKey] = draw;
      return draw;
    }

    private const int FolderOffset = 10000;

    private int GetResourceId(Resources res, int dictKey, string packageName)
    {
      bool forFolder = dictKey >= FolderOffset;
      int iconId = dictKey % FolderOffset;
      var name = (forFolder ? "icf" : "ic") + iconId.ToString("D2");
      int resId = res.GetIdentifier(name, "drawable", packageName);
      if ((forFolder) && (resId == 0)) //if no explicit folder icon was found, retry a normal icon
      {
        name = "ic" + iconId.ToString("D2");
        resId = res.GetIdentifier(name, "drawable", packageName);
      }
      //return what we found, may still be 0
      return resId;
    }

    private int GetDictionaryKey(PwIcon icon, bool forGroup)
    {

      return ((int)icon) + (forGroup ? FolderOffset : 0);
    }

    public Drawable GetIconDrawable(Context context, PwDatabase db, PwUuid icon)
    {
      InitBlank(context);
      if (icon.Equals(PwUuid.Zero))
      {
        return _blank;
      }
      Drawable draw;
      if (!_customIconMap.TryGetValue(icon, out draw))
      {
        Bitmap bitmap = db.GetCustomIcon(icon);

        // Could not understand custom icon
        if (bitmap == null)
        {
          return _blank;
        }

        draw = new BitmapDrawable(context.Resources, bitmap);
        _customIconMap[icon] = draw;
      }

      return draw;
    }



    public void Clear()
    {
      _standardIconMap.Clear();
      _customIconMap.Clear();
    }


  }
}

